#include <iostream>
#include <math.h>
using namespace std;

//to solve simple equation
class SimpleEquation
{
    public:
        SimpleEquation();
        virtual ~SimpleEquation();
        float a,b;
        void solve();
};
SimpleEquation::SimpleEquation()
{
    a=b=0;
}
SimpleEquation::~SimpleEquation()
{
}
void SimpleEquation::solve()
{
    if(a!=0)
        std::cout<<"the root of the equation is:"<<'\n'<<-b/a<<std::endl;
    else if(b!=0)
        std::cout<<"the equation has no root!"<<std::endl;
    else
        std::cout<<"the equation has incalculability roots!"<<std::endl;
}


//to solve quadratic equation
class QuadraticEquation
{
    public:
        QuadraticEquation();
        virtual ~QuadraticEquation();
        float a,b,c;
        void solve();
    private:
        float temp,temp1,temp2;
};
QuadraticEquation::QuadraticEquation()
{
    a=b=c=0;
    temp=temp1=temp2=0;
}
QuadraticEquation::~QuadraticEquation()
{
}
void QuadraticEquation::solve()
{
    temp=b*b-4*a*c;
    if(temp>0||temp==0)
    {
        temp1=(-b+sqrt(temp))/(2*a);
        temp2=(-b-sqrt(temp))/(2*a);
        std::cout<<"the equation has two real roots:"<<'\n'<<temp1<<'\t'<<temp2<<std::endl;
    }
    else if(temp<0)
    {
        temp1=-b/(2*a);
        temp2=sqrt(fabs(temp))/(2*a);
        std::cout<<"the equation has two complex roots:"<<'\n'<<temp1<<"+i"<<temp2<<'\t'<<temp1<<"-i"<<temp2<<std::endl;
    }
}

//to solve cubic equation;Shengjin's Theorems
class CubicEquation
{
    public:
        CubicEquation();
        virtual ~CubicEquation();
        float a,b,c,d;                  //coefficient
        int solve();
    private:
        float A,B,C,temp;               //discriminant
        float root1r,root2r,root3r;     //real part
        float root1i,root2i,root3i;     //imaginary part
        float cube(float);
};
CubicEquation::CubicEquation()
{
    a=b=c=d=0;
    A=B=C=temp=0;
    root1r=root2r=root3r=0;
    root1i=root2i=root3i=0;
}
CubicEquation::~CubicEquation()
{
}
int CubicEquation::solve()
{
    A=b*b-3*a*c;
    B=b*c-9*a*d;
    C=c*c-3*b*d;
    temp=B*B-4*A*C;                     //calculate the discriminants
    //std::cout<<a<<'\t'<<b<<'\t'<<c<<'\t'<<d<<std::endl;
    //std::cout<<A<<'\t'<<B<<'\t'<<C<<'\t'<<temp<<std::endl;
    if(fabs(A)<0.0001&&fabs(B)<0.0001)
    {
        //std::cout<<"A=0,B=0"<<std::endl;
        root1r=root2r=root3r=-b/(3*a);
        std::cout<<"the equation has three real roots:"<<'\n'<<root1r<<'\t'<<root2r<<'\t'<<root3r<<std::endl;
        return 0;
    }
    else if(temp>0.0001)
    {
        //std::cout<<"temp>0"<<std::endl;
        float y1=A*b+3*a*(-B+sqrt(B*B-4*A*C))/2;
        float y2=A*b+3*a*(-B-sqrt(B*B-4*A*C))/2;
        float y1cube,y2cube;                      //y1,y2 cube root
        y1cube=CubicEquation::cube(y1);
        y2cube=CubicEquation::cube(y2);
        //std::cout<<y1<<'\t'<<y2<<std::endl;
        //std::cout<<y1cubic<<'\t'<<y2cubic<<std::endl;
        //std::cout<<pow(y1,exponent)<<'\t'<<pow(y2,exponent)<<std::endl;
        root1r=(-b-y1cube-y2cube)/(3*a);
        root2r=root3r=(-2*b+y1cube+y2cube)/(6*a);
        root2i=root3i=sqrt(3)*fabs(y1cube-y2cube)/(6*a);
        std::cout<<"the equation has one real root and two complex roots:"<<'\n'<<root1r<<'\t'<<root2r<<"+i"<<root2i<<'\t'<<root3r<<"-i"<<root3i<<std::endl;
        return 0;
    }
    else if(fabs(temp)<0.0001||fabs(temp)==0.0001)
    {
        std::cout<<"temp=0"<<std::endl;
        float K=B/A;
        root1r=-b/a+K;
        root2r=root3r=-K/2;
        std::cout<<"the equation has three real roots:"<<'\n'<<root1r<<'\t'<<root2r<<'\t'<<root3r<<std::endl;
        return 0;
    }
    else if(temp<-0.0001)
    {
        std::cout<<"temp<0"<<std::endl;
        float T=(2*A*b-3*a*B)/(2*sqrt(A*A*A));
        float r=acos(T);
        root1r=(-b-2*sqrt(A)*cos(r/3))/(3*a);
        root2r=(-b+sqrt(A)*(cos(r/3)+sqrt(3)*sin(r/3)))/(3*a);
        root3r=(-b+sqrt(A)*(cos(r/3)-sqrt(3)*sin(r/3)))/(3*a);
        std::cout<<"the equation has three real roots:"<<'\n'<<root1r<<'\t'<<root2r<<'\t'<<root3r<<std::endl;
        return 0;
    }
    return 0;
}

float CubicEquation::cube(float y)
{
    if(y>0||y==0)
        return pow(y,0.333333);
    else
        return -pow(fabs(y),0.333333);
}


int main()
{
    int degree;     //the degree of the equation that you want to solve
    char idea;      //enter y when you want to exit
    while(1)
    {
        while(1)
        {
            std::cout << "Please enter the degree of the equation(1,2,3):" <<std::endl;
            std::cin >> degree;
            if(degree==1||degree==2||degree==3)
                break;
            std::cout<<"Error!Please reenter the degree!"<<std::endl;
        }
        SimpleEquation simple;
        QuadraticEquation quadratic;
        CubicEquation cubic;
        switch(degree)
        {

            case 1:
                //SimpleEquation simple;        //why can't i define the simple here?
                std::cout<<"Please enter the simple equation ax+b=0 coefficient a,b:"<<std::endl;
                std::cin>>simple.a>>simple.b;
                simple.solve();
                break;
            case 2:
                //QuadraticEquation quadratic;  //why can't i define the quardratic here?
                std::cout<<"Please enter the quadratic equation ax^2+bx+c=0 coefficient a,b,c:"<<std::endl;
                do
                {
                    std::cin>>quadratic.a>>quadratic.b>>quadratic.c;
                    if(quadratic.a==0)
                        std::cout<<"Error!Please reenter the coefficient a,b,c!"<<std::endl;
                }
                while(quadratic.a==0);
                quadratic.solve();
                break;
            case 3:
                //CubicEquation cubic;
                std::cout<<"Please enter the cubic equation ax^3+bx^2+cx+d=0 coefficient a,b,c,d:"<<std::endl;
                do
                {
                    std::cin>>cubic.a>>cubic.b>>cubic.c>>cubic.d;
                    if(cubic.a==0)
                        std::cout<<"Error!Please reenter the coefficient a,b,c,d!"<<std::endl;
                }
                while(cubic.a==0);
                cubic.solve();
                break;
        }
        std::cout<<"Do you want to exit the progream?-y/n?"<<std::endl;     //please enter 'y' or 'Y' to exit
        std::cin>>idea;
        if (idea=='y'||idea=='Y')
            break;
    }
    return 0;
}
